package com.bsoft.gol.hcs.specialist.service.impl;

import com.alibaba.fastjson.JSON;
import ctd.controller.exception.ControllerException;
import com.bsoft.gol.hcs.enumcase.*;
import hcn.base.Dept;
import hcn.base.Organization;
import hcn.util.BaseResponse;
import hcn.util.ResultCode;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;
import org.springframework.util.CollectionUtils;
import org.springframework.util.StringUtils;
import service.rpc.IDeptMainRpcService;
import service.rpc.IOrganizationRpcService;
import com.bsoft.gol.hcs.specialist.bean.response.ExecuteFactorResponse;
import com.bsoft.gol.hcs.specialist.bean.response.FactorData;
import com.bsoft.gol.hcs.specialist.dao.*;
import com.bsoft.gol.hcs.specialist.entity.*;
import com.bsoft.gol.hcs.specialist.service.IFollowUpCommonService;
import com.bsoft.gol.hcs.utils.*;
import com.bsoft.gol.hcs.visitrecord.dao.*;
import com.bsoft.gol.hcs.visitrecord.entity.VrSynchroSettings;

import java.util.*;

import static com.bsoft.gol.hcs.enumcase.FollowFactorTypeEnum.OUTPATIENT_DIAGNOSIS;
import static com.bsoft.gol.hcs.enumcase.VisitRecordEnum.getEnumByKey;

/**
 * @author fzy91
 * @title: FollowUpCommonServiceImpl
 * @projectName GOL-ssdev4
 * @description: 随访公共服务实现
 * @date 2022/5/279:32
 */
@Service
public class FollowUpCommonServiceImpl implements IFollowUpCommonService {

    private final static Logger logger = LoggerFactory.getLogger(FollowUpCommonServiceImpl.class);


    @Autowired
    private VrSynchroSettingsDAO synchroSettingsDAO;

    @Autowired
    private VrSurgicalRecordDAO surgicalRecordDAO;
    @Autowired
    private FusAnswerOperativeInfoDAO fusAnswerOperativeInfoDAO;

    @Autowired
    private VrVisitDiagnosisDAO vrVisitDiagnosisDAO;
    @Autowired
    private FusAnswerDiagnosisInfoDAO fusAnswerDiagnosisInfoDAO;

    @Autowired
    private FusCrucialIndexRecordDAO fusCrucialIndexRecordDAO;

    @Autowired
    private FollowUpRouteDetailFactorRelationDAO detailFactorRelationDAO;

    @Autowired
    private InspectReportRecordDAO inspectReportRecordDAO;
    @Autowired
    private FusAnswerInspectionReportInfoDAO fusAnswerInspectionReportInfoDAO;

    @Autowired
    private ExamReportDAO examReportDAO;

    @Autowired
    private FusAnswerCheckReportInfoDAO fusAnswerCheckReportInfoDAO;

    @Autowired
    private FollowUpPlanProduceRecordDAO produceRecordDAO;

    @Autowired
    private VrOutpatientVisitRecordDAO vrOutpatientVisitRecordDAO;
    @Autowired
    private FusAnswerOutpatientInfoDAO fusAnswerOutpatientInfoDAO;

    @Autowired
    private VrInpatientVisitRecordDAO vrInpatientVisitRecordDAO;
    @Autowired
    private FusAnswerInHospitalInfoDAO fusAnswerInHospitalInfoDAO;

    @Autowired
    private GroupRecordStagesPropertyDAO groupRecordStagesPropertyDAO;

    @Autowired
    private GroupRecordExtendPropertyDAO groupRecordExtendPropertyDAO;

    @Autowired
    private FusFactorDataRecordDAO fusFactorDataRecordDAO;

    @Autowired
    private IOrganizationRpcService organizationRpcService;

    @Autowired
    private IDeptMainRpcService deptMainRpcService;

    @Autowired
    private ProduceExecutionListDAO produceExecutionListDAO;

    @Autowired
    private VrSurgicalRecordDAO vrSurgicalRecordDAO;

    @Autowired
    private VrApplicationFormRecordDAO vrApplicationFormRecordDAO;

    @Autowired
    private VrDispensingRecordDAO vrDispensingRecordDAO;


    /**
     * 执行诊断因素
     *
     * @param followUpRouteDetailFactor 因素记录
     * @param isLoopExecute             循环执行机制 0 不执行 1 执行
     * @param followType                随访大类类型 1-专病随访，2-院后随访，3-满意度随访
     * @param patientIdList             病人id集合，如果传入不为空的话，可以根据传入的参数缩小检索范围
     * @return org.atag.core.base.BaseResponse<specialist.bean.response.ExecuteFactorResponse>
     * @throws
     * @Author:ChenJij
     */
    @Override
    public BaseResponse<ExecuteFactorResponse> executeFactorForDiagnosis(FollowUpRouteDetailFactor followUpRouteDetailFactor, Byte isLoopExecute, String followType, List<String> patientIdList) {
        ExecuteFactorResponse executeFactorResponse = new ExecuteFactorResponse();
        //查询因素详情列表
        List<FollowUpRouteDetailFactorRelation> detailFactorRelationList = detailFactorRelationDAO.queryFactorRelationByRouteDetailFactorId(followUpRouteDetailFactor.getRouteDetailFactorId(),
                followUpRouteDetailFactor.getRouteDetailId());
        if (CommonUtils.isEmpty(detailFactorRelationList)) {
            return BaseRespUtil.setResultSuccess(executeFactorResponse);
        }

        //因素id集合，就是诊断编码集合
        List<String> factoryIdList = new ArrayList<>();
        for (FollowUpRouteDetailFactorRelation relation : detailFactorRelationList) {
            factoryIdList.add(relation.getFactorDiseaseId());
        }

        Byte factorTime = followUpRouteDetailFactor.getFactorTime();
        Date[] dateSection = new Date[2];
        Byte factorType = followUpRouteDetailFactor.getFactorType();
        if (OUTPATIENT_DIAGNOSIS.getType().equals(factorType)) {
            dateSection = this.getBusinessTimeRange(followUpRouteDetailFactor.getFactorTimeType(),
                    followUpRouteDetailFactor.getFactorTimeValue(),
                    followUpRouteDetailFactor.getFactorTime(),
                    DiagnosisAndTreatmentDataTypeEnum.OUTPATIENT_RECORDS.getType());
        } else if (FollowFactorTypeEnum.IN_HOSPITAL_DIAGNOSIS.getType().equals(factorType) || FollowFactorTypeEnum.OUT_HOSPITAL_DIAGNOSIS.getType().equals(factorType)) {
            dateSection = this.getBusinessTimeRange(followUpRouteDetailFactor.getFactorTimeType(),
                    followUpRouteDetailFactor.getFactorTimeValue(),
                    followUpRouteDetailFactor.getFactorTime(),
                    DiagnosisAndTreatmentDataTypeEnum.HOSPITALIZATION_RECORDS.getType());
        }
        //factorType转换成diagnosisServiceType
        //factor_type 因素类别,1.门诊诊断 2.入院诊断 3.出院诊断 4.接诊医生 5.责任医生6.关联指标 7.手术名称 8.医嘱名称9
        //  .专病分期 10.专病拓展属性 11.门诊状态 12.住院状态 13 路径分支',
        //diagnosisServiceType 业务诊断类型：1入院诊断、2出院诊断、3门诊诊断、5其他诊断
        String diagnosisServiceType = "5";
        if (OUTPATIENT_DIAGNOSIS.getType().equals(factorType)) {
            diagnosisServiceType = "3";
        } else if (FollowFactorTypeEnum.IN_HOSPITAL_DIAGNOSIS.getType().equals(factorType)) {
            diagnosisServiceType = "1";
        } else if (FollowFactorTypeEnum.OUT_HOSPITAL_DIAGNOSIS.getType().equals(factorType)) {
            diagnosisServiceType = "2";
        }
        //查询诊断记录列表
        List<FactorData> factorDataList = vrVisitDiagnosisDAO.executeFactorForDiagnosis(factoryIdList,
                dateSection[0], dateSection[1], diagnosisServiceType, patientIdList,
                isLoopExecute, followUpRouteDetailFactor.getRouteDetailId(), followType);
        List<FactorData> factorDataAnswerList = fusAnswerDiagnosisInfoDAO.executeFactorForDiagnosis(factoryIdList,
                dateSection[0], dateSection[1], diagnosisServiceType, patientIdList,
                isLoopExecute, followUpRouteDetailFactor.getRouteDetailId(), followType);
        factorDataList.addAll(factorDataAnswerList);
        if (CommonUtils.isNotEmpty(factorDataList)) {
            //对factorDataList进行数据转换
            executeFactorResponse = this.factorDataTransform(factorDataList, followUpRouteDetailFactor);
        }
        return BaseRespUtil.setResultSuccess(executeFactorResponse);
    }


    /**
     * 执行手术因素
     *
     * @param followUpRouteDetailFactor 因素记录
     * @param isLoopExecute             循环执行机制 0 不执行 1 执行
     * @param followType                随访大类类型 1-专病随访，2-院后随访，3-满意度随访
     * @param patientIdList             病人id集合，如果传入不为空的话，可以根据传入的参数缩小检索范围
     * @return org.atag.core.base.BaseResponse<specialist.bean.response.ExecuteFactorResponse>
     * @throws
     * @Author:FangZhiYi
     */
    @Override
    public BaseResponse<ExecuteFactorResponse> executeFactorForOperation(FollowUpRouteDetailFactor followUpRouteDetailFactor, Byte isLoopExecute, String followType, List<String> patientIdList) {
        ExecuteFactorResponse executeFactorResponse = new ExecuteFactorResponse();
        Byte factorTime = followUpRouteDetailFactor.getFactorTime();
        Date[] dateSection = this.getBusinessTimeRange(followUpRouteDetailFactor.getFactorTimeType(), followUpRouteDetailFactor.getFactorTimeValue(),
                followUpRouteDetailFactor.getFactorTime(), DiagnosisAndTreatmentDataTypeEnum.SURGICAL_RECORDS.getType());
        //查询因素详情列表
        List<FollowUpRouteDetailFactorRelation> detailFactorRelationList = detailFactorRelationDAO.queryFactorRelationByRouteDetailFactorId(followUpRouteDetailFactor.getRouteDetailFactorId(),
                followUpRouteDetailFactor.getRouteDetailId());
        if (CommonUtils.isNotEmpty(detailFactorRelationList)) {
            List<String> operateIdList = new ArrayList<>();
            for (FollowUpRouteDetailFactorRelation detailFactorRelation : detailFactorRelationList) {
                operateIdList.add(detailFactorRelation.getFactorOperateId());
            }
            List<FactorData> factorDataList = surgicalRecordDAO.executeFactorForOperation(operateIdList, dateSection[0], dateSection[1], patientIdList, isLoopExecute, followUpRouteDetailFactor.getRouteDetailId(), followType);
            List<FactorData> factorDataListAnswer = fusAnswerOperativeInfoDAO.executeFactorForOperation(operateIdList, dateSection[0], dateSection[1], patientIdList, isLoopExecute, followUpRouteDetailFactor.getRouteDetailId(), followType);
            factorDataList.addAll(factorDataListAnswer);
            if (CommonUtils.isNotEmpty(factorDataList)) {
                //对factorDataList进行数据转换
                executeFactorResponse = this.factorDataTransform(factorDataList, followUpRouteDetailFactor);
            }
        }
        return BaseRespUtil.setResultSuccess(executeFactorResponse);
    }

    /**
     * 执行关联指标因素
     *
     * @param followUpRouteDetailFactor 因素记录
     * @param isLoopExecute             循环执行机制 0 不执行 1 执行
     * @param followType                随访大类类型 1-专病随访，2-院后随访，3-满意度随访
     * @param patientIdList             病人id集合，如果传入不为空的话，可以根据传入的参数缩小检索范围
     * @return org.atag.core.base.BaseResponse<specialist.bean.response.ExecuteFactorResponse>
     * @throws
     * @Author:FangZhiYi
     */
    @Override
    public BaseResponse<ExecuteFactorResponse> executeFactorForRelatedIndicators(FollowUpRouteDetailFactor followUpRouteDetailFactor, Byte isLoopExecute, String followType, List<String> patientIdList) {
        ExecuteFactorResponse executeFactorResponse = new ExecuteFactorResponse();
        Byte factorTime = followUpRouteDetailFactor.getFactorTime();
        //查询因素详情列表
        List<FollowUpRouteDetailFactorRelation> detailFactorRelationList = detailFactorRelationDAO.queryFactorRelationByRouteDetailFactorId(followUpRouteDetailFactor.getRouteDetailFactorId(),
                followUpRouteDetailFactor.getRouteDetailId());
        //最终结果集
        List<FactorData> factorDataList = new ArrayList<>();
        //每个因素详情求得的结果集（同步数据）
        List<FactorData> temp = new ArrayList<>();
        //每个因素详情求得的结果集(表单答案)
        List<FactorData> tempAnswer = new ArrayList<>();
        if (CommonUtils.isNotEmpty(detailFactorRelationList)) {
            Date[] dateSection = new Date[2];
            for (FollowUpRouteDetailFactorRelation factorRelation : detailFactorRelationList) {
                if(!StringUtils.isEmpty(factorRelation.getFactorResultOne())){
                    FusCrucialIndexRecord indexRecord = fusCrucialIndexRecordDAO.get(factorRelation.getFactorId());
                    //4检验
                    if ("4".equals(indexRecord.getIndexType())) {
                        //获取因素处理业务时间区间
                        dateSection = this.getBusinessTimeRange(followUpRouteDetailFactor.getFactorTimeType(), followUpRouteDetailFactor.getFactorTimeValue(),
                                followUpRouteDetailFactor.getFactorTime(), DiagnosisAndTreatmentDataTypeEnum.INSPECTION_REPORT.getType());
                        temp = inspectReportRecordDAO.executeFactorForRelatedIndicators(factorRelation, dateSection[0], dateSection[1], patientIdList, isLoopExecute, followUpRouteDetailFactor.getRouteDetailId(), followType);
                        tempAnswer = fusAnswerInspectionReportInfoDAO.executeFactorForRelatedIndicators(factorRelation, dateSection[0], dateSection[1], patientIdList, isLoopExecute, followUpRouteDetailFactor.getRouteDetailId(), followType);
                        temp.addAll(tempAnswer);
                    }
                    //5检查
                    if ("5".equals(indexRecord.getIndexType())) {
                        //获取因素处理业务时间区间
                        dateSection = this.getBusinessTimeRange(followUpRouteDetailFactor.getFactorTimeType(), followUpRouteDetailFactor.getFactorTimeValue(),
                                followUpRouteDetailFactor.getFactorTime(), DiagnosisAndTreatmentDataTypeEnum.CHECK_REPORT.getType());
                        temp = examReportDAO.executeFactorForRelatedIndicators(factorRelation, dateSection[0], dateSection[1], patientIdList, isLoopExecute, followUpRouteDetailFactor.getRouteDetailId(), followType);
                        tempAnswer = fusAnswerCheckReportInfoDAO.executeFactorForRelatedIndicators(factorRelation, dateSection[0], dateSection[1], patientIdList, isLoopExecute, followUpRouteDetailFactor.getRouteDetailId(), followType);
                        temp.addAll(tempAnswer);
                    }
                    //TODO 病理，体征
                    factorDataList.addAll(temp);
                }
            }
        }
        if (CommonUtils.isNotEmpty(factorDataList)) {
            //对factorDataList进行数据转换
            executeFactorResponse = this.factorDataTransform(factorDataList, followUpRouteDetailFactor);
        }
        return BaseRespUtil.setResultSuccess(executeFactorResponse);
    }

    /**
     * 执行路径分支因素
     *
     * @param followUpRouteDetailFactor 因素记录
     * @param isLoopExecute             循环执行机制 0 不执行 1 执行
     * @param followType                随访大类类型 1-专病随访，2-院后随访，3-满意度随访
     * @param patientIdList             病人id集合，如果传入不为空的话，可以根据传入的参数缩小检索范围
     * @return org.atag.core.base.BaseResponse<specialist.bean.response.ExecuteFactorResponse>
     * @throws
     * @Author:FangZhiYi
     */
    @Override
    public BaseResponse<ExecuteFactorResponse> executeFactorForPathBranch(FollowUpRouteDetailFactor followUpRouteDetailFactor, Byte isLoopExecute, String followType, List<String> patientIdList) {
        ExecuteFactorResponse executeFactorResponse = new ExecuteFactorResponse();
        //随访大类不为专病随访直接返回
        if (!FollowTypeEnum.FUS_SPECIALIST.getType().equals(followType)) {
            BaseRespUtil.setResultSuccess(executeFactorResponse);
        }
        //查询因素详情列表
        List<FollowUpRouteDetailFactorRelation> detailFactorRelationList = detailFactorRelationDAO.queryFactorRelationByRouteDetailFactorId(followUpRouteDetailFactor.getRouteDetailFactorId(),
                followUpRouteDetailFactor.getRouteDetailId());
        //最终结果集
        List<FactorData> factorDataList = new ArrayList<>();
        if (CommonUtils.isNotEmpty(detailFactorRelationList)) {
            factorDataList = produceRecordDAO.executeFactorForPathBranch(detailFactorRelationList.get(0), patientIdList, isLoopExecute, followUpRouteDetailFactor.getRouteDetailId(), followType);
        }
        //获取因素处理业务时间区间
        if (CommonUtils.isNotEmpty(factorDataList)) {
            //对factorDataList进行数据转换
            executeFactorResponse = this.factorDataTransform(factorDataList, followUpRouteDetailFactor);
        }
        return BaseRespUtil.setResultSuccess(executeFactorResponse);
    }

    /**
     * 执行接诊医生因素
     *
     * @param followUpRouteDetailFactor 因素记录
     * @param isLoopExecute             循环执行机制 0 不执行 1 执行
     * @param followType                随访大类类型 1-专病随访，2-院后随访，3-满意度随访
     * @param patientIdList             病人id集合，如果传入不为空的话，可以根据传入的参数缩小检索范围
     * @return org.atag.core.base.BaseResponse<specialist.bean.response.ExecuteFactorResponse>
     * @throws
     * @Author:ChenJij
     */
    @Override
    public BaseResponse<ExecuteFactorResponse> executeFactorForAttendingDoctor(FollowUpRouteDetailFactor followUpRouteDetailFactor, Byte isLoopExecute, String followType, List<String> patientIdList) {
        ExecuteFactorResponse executeFactorResponse = new ExecuteFactorResponse();
        //查询因素详情列表
        List<FollowUpRouteDetailFactorRelation> detailFactorRelationList = detailFactorRelationDAO.queryFactorRelationByRouteDetailFactorId(followUpRouteDetailFactor.getRouteDetailFactorId(),
                followUpRouteDetailFactor.getRouteDetailId());
        if (CommonUtils.isEmpty(detailFactorRelationList)) {
            return BaseRespUtil.setResultSuccess(executeFactorResponse);
        }

        //因素id集合，就是诊断编码集合
        List<String> factoryIdList = new ArrayList<>();
        for (FollowUpRouteDetailFactorRelation relation : detailFactorRelationList) {
            factoryIdList.add(relation.getFactorDoctorId());
        }

        Byte factorTime = followUpRouteDetailFactor.getFactorTime();
        Date[] dateSection = new Date[2];
        if (OUTPATIENT_DIAGNOSIS.getType().equals(followUpRouteDetailFactor.getFactorType())) {
            dateSection = this.getBusinessTimeRange(followUpRouteDetailFactor.getFactorTimeType(), followUpRouteDetailFactor.getFactorTimeValue(),
                    followUpRouteDetailFactor.getFactorTime(), DiagnosisAndTreatmentDataTypeEnum.OUTPATIENT_RECORDS.getType());
        } else if (FollowFactorTypeEnum.IN_HOSPITAL_DIAGNOSIS.getType().equals(followUpRouteDetailFactor.getFactorType()) || FollowFactorTypeEnum.OUT_HOSPITAL_DIAGNOSIS.getType().equals(followUpRouteDetailFactor.getFactorType())) {
            dateSection = this.getBusinessTimeRange(followUpRouteDetailFactor.getFactorTimeType(), followUpRouteDetailFactor.getFactorTimeValue(),
                    followUpRouteDetailFactor.getFactorTime(), DiagnosisAndTreatmentDataTypeEnum.HOSPITALIZATION_RECORDS.getType());
        }
        //查询门诊就诊记录列表
        List<FactorData> factorDataList = vrOutpatientVisitRecordDAO.executeFactorForOutpatient(factoryIdList,
                dateSection[0], dateSection[1], followUpRouteDetailFactor.getFactorType().toString(), patientIdList, isLoopExecute, followUpRouteDetailFactor.getRouteDetailId(), followType);
        List<FactorData> factorDataListAnswer = fusAnswerOutpatientInfoDAO.executeFactorForOutpatient(factoryIdList,
                dateSection[0], dateSection[1], followUpRouteDetailFactor.getFactorType().toString(), patientIdList, isLoopExecute, followUpRouteDetailFactor.getRouteDetailId(), followType);
        factorDataList.addAll(factorDataListAnswer);
        if (CommonUtils.isNotEmpty(factorDataList)) {
            //对factorDataList进行数据转换
            executeFactorResponse = this.factorDataTransform(factorDataList, followUpRouteDetailFactor);
        }
        return BaseRespUtil.setResultSuccess(executeFactorResponse);
    }

    /**
     * 执行责任医生因素
     *
     * @param followUpRouteDetailFactor 因素记录
     * @param isLoopExecute             循环执行机制 0 不执行 1 执行
     * @param followType                随访大类类型 1-专病随访，2-院后随访，3-满意度随访
     * @param patientIdList             病人id集合，如果传入不为空的话，可以根据传入的参数缩小检索范围
     * @return org.atag.core.base.BaseResponse<specialist.bean.response.ExecuteFactorResponse>
     * @throws
     * @Author:ChenJij
     */
    @Override
    public BaseResponse<ExecuteFactorResponse> executeFactorForResponsibleDoctor(FollowUpRouteDetailFactor followUpRouteDetailFactor, Byte isLoopExecute, String followType, List<String> patientIdList) {
        ExecuteFactorResponse executeFactorResponse = new ExecuteFactorResponse();
        //查询因素详情列表
        List<FollowUpRouteDetailFactorRelation> detailFactorRelationList = detailFactorRelationDAO.queryFactorRelationByRouteDetailFactorId(followUpRouteDetailFactor.getRouteDetailFactorId(),
                followUpRouteDetailFactor.getRouteDetailId());
        if (CommonUtils.isEmpty(detailFactorRelationList)) {
            return BaseRespUtil.setResultSuccess(executeFactorResponse);
        }

        //因素id集合，就是责任医生代码集合
        List<String> factoryIdList = new ArrayList<>();
        for (FollowUpRouteDetailFactorRelation relation : detailFactorRelationList) {
            factoryIdList.add(relation.getFactorDoctorId());
        }

        Byte factorTime = followUpRouteDetailFactor.getFactorTime();
        Date[] dateSection = new Date[2];
        if (OUTPATIENT_DIAGNOSIS.getType().equals(followUpRouteDetailFactor.getFactorType())) {
            dateSection = this.getBusinessTimeRange(followUpRouteDetailFactor.getFactorTimeType(), followUpRouteDetailFactor.getFactorTimeValue(),
                    followUpRouteDetailFactor.getFactorTime(), DiagnosisAndTreatmentDataTypeEnum.OUTPATIENT_RECORDS.getType());
        } else if (FollowFactorTypeEnum.IN_HOSPITAL_DIAGNOSIS.getType().equals(followUpRouteDetailFactor.getFactorType()) || FollowFactorTypeEnum.OUT_HOSPITAL_DIAGNOSIS.getType().equals(followUpRouteDetailFactor.getFactorType())) {
            dateSection = this.getBusinessTimeRange(followUpRouteDetailFactor.getFactorTimeType(), followUpRouteDetailFactor.getFactorTimeValue(),
                    followUpRouteDetailFactor.getFactorTime(), DiagnosisAndTreatmentDataTypeEnum.HOSPITALIZATION_RECORDS.getType());
        }
        //查询住院记录列表
        List<FactorData> factorDataList = vrInpatientVisitRecordDAO.executeFactorForInpatient(factoryIdList,
                dateSection[0], dateSection[1], followUpRouteDetailFactor.getFactorType().toString(), patientIdList, isLoopExecute, followUpRouteDetailFactor.getRouteDetailId(), followType);
        List<FactorData> factorDataAnswerList = fusAnswerInHospitalInfoDAO.executeFactorForInpatient(factoryIdList,
                dateSection[0], dateSection[1], followUpRouteDetailFactor.getFactorType().toString(), patientIdList, isLoopExecute, followUpRouteDetailFactor.getRouteDetailId(), followType);
        factorDataList.addAll(factorDataAnswerList);
        if (CommonUtils.isNotEmpty(factorDataList)) {
            //对factorDataList进行数据转换
            executeFactorResponse = this.factorDataTransform(factorDataList, followUpRouteDetailFactor);
        }
        return BaseRespUtil.setResultSuccess(executeFactorResponse);
    }

    /**
     * 执行专病分期因素
     *
     * @param followUpRouteDetailFactor 因素记录
     * @param isLoopExecute             循环执行机制 0 不执行 1 执行
     * @param followType                随访大类类型 1-专病随访，2-院后随访，3-满意度随访
     * @param patientIdList             病人id集合，如果传入不为空的话，可以根据传入的参数缩小检索范围
     * @return org.atag.core.base.BaseResponse<specialist.bean.response.ExecuteFactorResponse>
     * @throws
     * @Author:ChenJij
     */
    @Override
    public BaseResponse<ExecuteFactorResponse> executeFactorForSpecificDiseaseStage(FollowUpRouteDetailFactor followUpRouteDetailFactor, Byte isLoopExecute, String followType, List<String> patientIdList) {
        ExecuteFactorResponse executeFactorResponse = new ExecuteFactorResponse();
        //查询因素详情列表
        List<FollowUpRouteDetailFactorRelation> detailFactorRelationList = detailFactorRelationDAO.queryFactorRelationByRouteDetailFactorId(followUpRouteDetailFactor.getRouteDetailFactorId(),
                followUpRouteDetailFactor.getRouteDetailId());
        if (CommonUtils.isEmpty(detailFactorRelationList)) {
            return BaseRespUtil.setResultSuccess(executeFactorResponse);
        }

        //因素id集合，就是专病分期编码集合
        List<String> factoryIdList = new ArrayList<>();
        for (FollowUpRouteDetailFactorRelation relation : detailFactorRelationList) {
            factoryIdList.add(relation.getFactorSpecialistId());
        }

        Byte factorTime = followUpRouteDetailFactor.getFactorTime();
        Date[] dateSection = new Date[2];
        if (OUTPATIENT_DIAGNOSIS.getType().equals(followUpRouteDetailFactor.getFactorType())) {
            dateSection = this.getBusinessTimeRange(followUpRouteDetailFactor.getFactorTimeType(), followUpRouteDetailFactor.getFactorTimeValue(),
                    followUpRouteDetailFactor.getFactorTime(), DiagnosisAndTreatmentDataTypeEnum.OUTPATIENT_RECORDS.getType());
        } else if (FollowFactorTypeEnum.IN_HOSPITAL_DIAGNOSIS.getType().equals(followUpRouteDetailFactor.getFactorType()) || FollowFactorTypeEnum.OUT_HOSPITAL_DIAGNOSIS.getType().equals(followUpRouteDetailFactor.getFactorType())) {
            dateSection = this.getBusinessTimeRange(followUpRouteDetailFactor.getFactorTimeType(), followUpRouteDetailFactor.getFactorTimeValue(),
                    followUpRouteDetailFactor.getFactorTime(), DiagnosisAndTreatmentDataTypeEnum.HOSPITALIZATION_RECORDS.getType());
        }
        //查询入组专病分期记录列表
        List<FactorData> factorDataList = groupRecordStagesPropertyDAO.executeFactorForDiseasePeriod(factoryIdList,
                dateSection[0], dateSection[1], patientIdList, isLoopExecute, followUpRouteDetailFactor.getRouteDetailId(), followType);
        if (CommonUtils.isNotEmpty(factorDataList)) {
            //对factorDataList进行数据转换
            executeFactorResponse = this.factorDataTransform(factorDataList, followUpRouteDetailFactor);
        }
        return BaseRespUtil.setResultSuccess(executeFactorResponse);
    }

    /**
     * 处理因素列表得到人员信息集合和因素数据集合
     *
     * @param followUpRoute
     * @param isLoopExecute
     * @param followUpRouteDetailFactors
     * @param previousList
     * @param patientInfoMap
     * @return void
     * @throws
     * @author tongtp
     * @date 2022/5/30 14:51
     */
    @Override
    public void handleFactorList(FollowUpRoute followUpRoute, Byte isLoopExecute,
                                 List<FollowUpRouteDetailFactor> followUpRouteDetailFactors,
                                 List<String> previousList, Map<String, List<FactorData>> patientInfoMap) throws ControllerException {
        List<String> currentList = new ArrayList<>();
        boolean currentInit = false;
        //门诊就诊、住院状态的时间起点是根据其他因素的时间计算的
        //所以遇到门诊就诊、住院状态先存着，直到遇到or或最后一个因素执行完了再处理
        List<FollowUpRouteDetailFactor> statusFactorList = new ArrayList<>();
        for (int i = 0; i < followUpRouteDetailFactors.size(); i++) {
            FollowUpRouteDetailFactor followUpRouteDetailFactor = followUpRouteDetailFactors.get(i);
            //第一条是不选择运算符的,所以直接走and的逻辑
            if (i == 0 ||
                    FactorConditionTypeEnum.AND.getType().equals(followUpRouteDetailFactor.getFactorConditionType())) {
                if (FollowFactorTypeEnum.OUTPATIENT_STATUS.getType().equals(followUpRouteDetailFactor.getFactorType())
                        || FollowFactorTypeEnum.INPATIENT_STATUS.getType().equals(followUpRouteDetailFactor.getFactorType())) {
                    //门诊就诊、住院状态的时间起点是根据其他因素的时间计算的
                    //所以遇到门诊就诊、住院状态先存着，直到遇到or或最后一个因素执行完了再处理
                    statusFactorList.add(followUpRouteDetailFactor);
                } else {
                    //处理运算符是and的因素
                    currentInit = handleFactorForAnd(followUpRoute, isLoopExecute, currentList, currentInit,
                            followUpRouteDetailFactor, patientInfoMap);
                }
            } else if (FactorConditionTypeEnum.OR.getType().equals(followUpRouteDetailFactor.getFactorConditionType())) {
                //遇到or，如果statusFactorList不为空，则执行这些因素
                currentInit = handleStatusFactorList(followUpRoute, isLoopExecute, currentList, currentInit,
                        statusFactorList, patientInfoMap);
                //currentList合并到数据集合previousList中
                previousList.addAll(currentList);
                currentList.clear();
                if (FollowFactorTypeEnum.OUTPATIENT_STATUS.getType().equals(followUpRouteDetailFactor.getFactorType())
                        || FollowFactorTypeEnum.INPATIENT_STATUS.getType().equals(followUpRouteDetailFactor.getFactorType())) {
                    //门诊就诊、住院状态的时间起点是根据其他因素的时间计算的
                    //所以遇到门诊就诊、住院状态先存着，直到遇到or或最后一个因素执行完了再处理
                    statusFactorList.add(followUpRouteDetailFactor);
                    currentInit = false;
                } else {
                    //调用因素执行服务
                    ExecuteFactorResponse factorResponse = executeFactor(followUpRouteDetailFactor,
                            isLoopExecute, followUpRoute,
                            currentList, currentInit, patientInfoMap);
                    currentList.addAll(factorResponse.getPatientIdList());
                    //处理因素满足的人员因素数据
                    handlePatientInfoMap(currentList, patientInfoMap, factorResponse.getFactorDataMap());
                }
            }
            if (i == followUpRouteDetailFactors.size() - 1) {
                //最后一个因素执行完，如果statusFactorList不为空，则执行这些因素
                currentInit = handleStatusFactorList(followUpRoute, isLoopExecute, currentList, currentInit,
                        statusFactorList, patientInfoMap);
                previousList.addAll(currentList);
                currentList.clear();
            }
        }
    }

    /**
     * 得到开始时间-第一次随访计划的计划执行时间
     *
     * @param followUpRouteDetail 子路径
     * @param factorDataList      因素数据集合
     * @param followType          随访大类类型 1-专病随访，2-院后随访，3-满意度随访
     * @param auditTime           入组时间，专病随访必传
     * @param recordTime          就诊类型记录时间，院后和满意度必传
     * @return java.util.Date
     * @throws
     * @author tongtp
     * @date 2022/6/1 10:43
     */
    @Override
    public Date getStartPlanTime(FollowUpRouteDetail followUpRouteDetail,
                                 List<FactorData> factorDataList, String followType,
                                 Date auditTime, Date recordTime) throws ControllerException {
        if (FollowTypeEnum.FUS_SPECIALIST.getType().equals(followType)) {
            if (auditTime == null) {
                throw new ControllerException(ResultCode.ERROR, "专病随访入组时间必传");
            }
        } else if (recordTime == null) {
            throw new ControllerException(ResultCode.ERROR, "院后随访和满意度随访就诊类型记录时间必传");
        }
        //开始时间：必输，首次随访计划时间，入径时间即为，当运算符是and时，
        //取满足开始因素触发生成计划的因素和入组时间、就诊类型对应时间中所对应的时间点的最晚时间，
        //当运算符为or时，取满足的所有因素对应的时间的最早时间和入组时间、就诊类型对应时间比较，
        //取晚的时间；当没有选择任何开始因素时，专病随访为入组时间；院后/满意度取就诊类型对应时间
        Date previousTime = null;
        if (CommonUtils.isNotEmpty(factorDataList)) {
            Date currentTime = null;
            boolean currentInit = false;
            //实现排序，因为执行因素的时候,门诊就诊和住院状态的因素是会排在同组因素后面执行的，所以在算因素时间时要还原原有排序计算
            Collections.sort(factorDataList);
            for (int i = 0; i < factorDataList.size(); i++) {
                FactorData factorData = factorDataList.get(i);
                if (FactorConditionTypeEnum.AND.getType().equals(factorData.getFactorConditionType())) {
                    if (!currentInit) {
                        currentTime = getFactorDate(factorData);
                        currentInit = true;
                    } else {
                        currentTime = DateTimeUtil.getMaxDate(currentTime, getFactorDate(factorData));
                    }
                } else if (FactorConditionTypeEnum.OR.getType().equals(factorData.getFactorConditionType())) {
                    previousTime = DateTimeUtil.getMinDate(previousTime, currentTime);
                    currentTime = getFactorDate(factorData);
                }
                if (i == factorDataList.size() - 1) {
                    //最后一个因素执行完，处理时间
                    previousTime = DateTimeUtil.getMinDate(previousTime, currentTime);
                }
            }
        }
        if (FollowTypeEnum.FUS_SPECIALIST.getType().equals(followType)) {
            previousTime = DateTimeUtil.getMaxDate(previousTime, auditTime);
        } else {
            previousTime = DateTimeUtil.getMaxDate(previousTime, recordTime);
        }
        //时间节点长度
        Integer timeNodeSize = followUpRouteDetail.getTimeNodeSize();
        //时间节点长度单位，1日 2周 3月
        Byte timeNodeSizeUnit = followUpRouteDetail.getTimeNodeSizeUnit();
        //时间间隔-天数
        Integer timeInterval = 0;
        switch (timeNodeSizeUnit) {
            case 1:
                timeInterval = timeNodeSize;
                break;
            case 2:
                timeInterval = timeNodeSize * 7;
                break;
            case 3:
                timeInterval = timeNodeSize * 30;
                break;
            default:
                break;
        }
        Calendar instance = Calendar.getInstance();
        instance.setTime(previousTime);
        instance.add(Calendar.DAY_OF_YEAR, timeInterval);
        return instance.getTime();
    }


    /**
     * 执行门诊（住院）状态因素
     *
     * @param followUpRouteDetailFactor 因素记录
     * @param isLoopExecute             循环执行机制 0 不执行 1 执行
     * @param followType                随访大类类型 1-专病随访，2-院后随访，3-满意度随访
     * @param patientIdList             病人id集合，如果传入不为空的话，可以根据传入的参数缩小检索范围
     * @param patientFactorTimeMap      病人因素时间集合，key是病人id(patientId)，value是同组(and相连的因素即为同组)其他因素的因素时间最晚的那个
     * @return org.atag.core.base.BaseResponse<specialist.bean.response.ExecuteFactorResponse>
     * @throws
     * @Author:FangZhiyi
     */
    @Override
    public BaseResponse<ExecuteFactorResponse> executeFactorForOutpatientInpatientStatus(FollowUpRouteDetailFactor followUpRouteDetailFactor, Byte isLoopExecute, String followType, List<String> patientIdList,
                                                                                         Map<String, Date> patientFactorTimeMap) {
        ExecuteFactorResponse executeFactorResponse = new ExecuteFactorResponse();
        //门诊类型
        Byte factorType = followUpRouteDetailFactor.getFactorType();
        //因素时间状态 门诊/住院状态时 必填 1 是 2 否
        Byte factorTimeStatus = followUpRouteDetailFactor.getFactorTimeStatus();
        ///因素时间
        Byte factorTime = followUpRouteDetailFactor.getFactorTime();
        Date[] dateSection = new Date[2];
        //查询因素详情列表
        List<FollowUpRouteDetailFactorRelation> detailFactorRelationList =
                detailFactorRelationDAO.queryFactorRelationByRouteDetailFactorId(followUpRouteDetailFactor.getRouteDetailFactorId(),
                        followUpRouteDetailFactor.getRouteDetailId());
        //最终结果集
        List<FactorData> factorDataList = new ArrayList<>();
        List<FactorData> factorDataAnswerList = new ArrayList<>();
        //每个因素详情求得的结果集
        List<String> deptIdList = new ArrayList<>();
        if (CommonUtils.isNotEmpty(detailFactorRelationList)) {
            for (FollowUpRouteDetailFactorRelation factorRelation : detailFactorRelationList) {
                deptIdList.add(factorRelation.getFactorDeptId());
            }
        }
        //门诊
        if (FollowFactorTypeEnum.OUTPATIENT_STATUS.getType().equals(factorType)) {
            if (null != factorTime) {
                dateSection = this.getBusinessTimeRange(followUpRouteDetailFactor.getFactorTimeType(), followUpRouteDetailFactor.getFactorTimeValue(),
                        followUpRouteDetailFactor.getFactorTime(), DiagnosisAndTreatmentDataTypeEnum.OUTPATIENT_RECORDS.getType());
                // 1.是+满：找出往前推X天。这天之前有就诊记录天的人
                if (FactorTimeStatusEnum.YES.getType().equals(factorTimeStatus) && FactorTimeEnum.getEnumByKey(factorTime).getFactorTimeType() == 1) {
                    factorDataList = vrOutpatientVisitRecordDAO.executeFactorForOutpatientStatus(deptIdList, dateSection[1], patientIdList, isLoopExecute, followUpRouteDetailFactor.getRouteDetailId(), followType);
                    factorDataAnswerList = fusAnswerOutpatientInfoDAO.executeFactorForOutpatientStatus(deptIdList, dateSection[1], patientIdList, isLoopExecute, followUpRouteDetailFactor.getRouteDetailId(), followType);
                    factorDataList.addAll(factorDataAnswerList);
                }
                // 2.是+内：找出往前推X天。这天到现在有就诊记录天的人
                if (FactorTimeStatusEnum.YES.getType().equals(factorTimeStatus) && FactorTimeEnum.getEnumByKey(factorTime).getFactorTimeType() == 2) {
                    factorDataList = vrOutpatientVisitRecordDAO.executeFactorForOutpatientStatus(deptIdList, dateSection[0], dateSection[1], patientIdList, isLoopExecute, followUpRouteDetailFactor.getRouteDetailId(), followType);
                    factorDataAnswerList = fusAnswerOutpatientInfoDAO.executeFactorForOutpatientStatus(deptIdList, dateSection[0], dateSection[1], patientIdList, isLoopExecute, followUpRouteDetailFactor.getRouteDetailId(), followType);
                    factorDataList.addAll(factorDataAnswerList);
                }
                //3.否+满：没有这种设置
                if (FactorTimeStatusEnum.NO.getType().equals(factorTimeStatus) && FactorTimeEnum.getEnumByKey(factorTime).getFactorTimeType() == 1) {
                    factorDataList = null;
                }
                // 4.否+内：找出往前推X天。这天到现在没有就诊记录天的人
                if (FactorTimeStatusEnum.NO.getType().equals(factorTimeStatus) && FactorTimeEnum.getEnumByKey(factorTime).getFactorTimeType() == 2) {
                    if (CommonUtils.isNotEmpty(patientIdList)) {
                        // 这段时间内无门诊记录的患者FactorData列表
                        List<FactorData> resultFactorData = new ArrayList<>();
                        for (String patientId : patientIdList) {
                            Date startTime = DateTimeUtil.getMinDate( dateSection[0],patientFactorTimeMap.get(patientId));
                            int result = vrOutpatientVisitRecordDAO.executeFactorForOutpatientStatus(patientId, startTime);
                            if (result == 0) {
                                FactorData factorData = new FactorData();
                                factorData.setPatientId(patientId);
                                factorData.setDataSource(null);
                                resultFactorData.add(factorData);
                            }
                        }
                        factorDataList = resultFactorData;
                    }else{
                        factorDataList=null;
                    }
                }
            }
            // 5.存在门诊就诊记录的人
            if (FactorTimeStatusEnum.YES.getType().equals(factorTimeStatus) && null == factorTime) {
                factorDataList = vrOutpatientVisitRecordDAO.executeFactorForOutpatientStatus(deptIdList, null, null, patientIdList, isLoopExecute, followUpRouteDetailFactor.getRouteDetailId(), followType);
                factorDataAnswerList = fusAnswerOutpatientInfoDAO.executeFactorForOutpatientStatus(deptIdList, null, null, patientIdList, isLoopExecute, followUpRouteDetailFactor.getRouteDetailId(), followType);
                factorDataList.addAll(factorDataAnswerList);
            }
            // 6.不存在门诊就诊记录的人
            if (FactorTimeStatusEnum.NO.getType().equals(factorTimeStatus) && null == factorTime) {
                if (CommonUtils.isNotEmpty(patientIdList)) {
                    //这段时间内无住院门诊的患者ID集合
                    List<String> resultList = new ArrayList<String>();
                    factorDataList = vrOutpatientVisitRecordDAO.executeFactorForOutpatientStatus(deptIdList, null, null, patientIdList, isLoopExecute, followUpRouteDetailFactor.getRouteDetailId(), followType);
                    factorDataAnswerList = fusAnswerOutpatientInfoDAO.executeFactorForOutpatientStatus(deptIdList, null, null, patientIdList, isLoopExecute, followUpRouteDetailFactor.getRouteDetailId(), followType);
                    factorDataList.addAll(factorDataAnswerList);
                    //这段时间内有门诊记录的患者ID集合
                    Set<String> tempList = new HashSet<>();
                    if (CommonUtils.isNotEmpty(patientIdList)) {
                        for (FactorData factorData : factorDataList) {
                            tempList.add(factorData.getPatientId());
                        }
                    }
                    //求差集
                    resultList.addAll(patientIdList);
                    resultList.removeAll(tempList);
                    if (CommonUtils.isNotEmpty(resultList)) {
                        // 这段时间内无门诊记录的患者FactorData列表
                        List<FactorData> resultFactorData = new ArrayList<>();
                        for (String patientId : resultList) {
                            FactorData factorData = new FactorData();
                            factorData.setPatientId(patientId);
                            resultFactorData.add(factorData);
                        }
                        factorDataList.addAll(resultFactorData);
                    }
                }
                factorDataList = null;
            }
        }
        //住院
        if (FollowFactorTypeEnum.INPATIENT_STATUS.getType().equals(factorType)) {
            if (null != factorTime) {
                dateSection = this.getBusinessTimeRange(followUpRouteDetailFactor.getFactorTimeType(), followUpRouteDetailFactor.getFactorTimeValue(),
                        followUpRouteDetailFactor.getFactorTime(), DiagnosisAndTreatmentDataTypeEnum.HOSPITALIZATION_RECORDS.getType());
                // 1.是+满：当前在院且当前时间-入院时间的差>X天的人
                if (FactorTimeStatusEnum.YES.getType().equals(factorTimeStatus) && FactorTimeEnum.getEnumByKey(factorTime).getFactorTimeType() == 1) {
                    factorDataList = vrInpatientVisitRecordDAO.executeFactorForInpatientStatus(deptIdList, dateSection[0], dateSection[1], patientIdList, true, isLoopExecute, followUpRouteDetailFactor.getRouteDetailId(), followType);
                }
                // 2.是+内：没有这种设置
                if (FactorTimeStatusEnum.YES.getType().equals(factorTimeStatus) && FactorTimeEnum.getEnumByKey(factorTime).getFactorTimeType() == 2) {
                    factorDataList = null;
                }
                //33.否+满：当前出院且当前时间-X天的差>出院时间天的人
                if (FactorTimeStatusEnum.NO.getType().equals(factorTimeStatus) && FactorTimeEnum.getEnumByKey(factorTime).getFactorTimeType() == 1) {
                    factorDataList = vrInpatientVisitRecordDAO.executeFactorForInpatientStatus(deptIdList, dateSection[1], patientIdList, isLoopExecute, followUpRouteDetailFactor.getRouteDetailId(), followType);
                    factorDataAnswerList = fusAnswerInHospitalInfoDAO.executeFactorForInpatientStatus(deptIdList, dateSection[1], patientIdList, isLoopExecute, followUpRouteDetailFactor.getRouteDetailId(), followType);
                    factorDataList.addAll(factorDataAnswerList);
                }
                // 4.否+内：往前推X天，无住院记录的人
                if (FactorTimeStatusEnum.NO.getType().equals(factorTimeStatus) && FactorTimeEnum.getEnumByKey(factorTime).getFactorTimeType() == 2) {
                    if (CommonUtils.isNotEmpty(patientIdList)) {
                        // 这段时间内无门诊记录的患者FactorData列表
                        List<FactorData> resultFactorData = new ArrayList<>();
                        for (String patientId : patientIdList) {
                            Date startTime =  DateTimeUtil.getMinDate( dateSection[0],patientFactorTimeMap.get(patientId));
                            int result = vrInpatientVisitRecordDAO.executeFactorForOutpatientStatus(patientId, startTime);
                            if (result == 0) {
                                FactorData factorData = new FactorData();
                                factorData.setPatientId(patientId);
                                factorData.setDataSource(null);
                                resultFactorData.add(factorData);
                            }
                        }
                        factorDataList = resultFactorData;
                    }else{
                        factorDataList=null;
                    }
                }
            }
            // 5.存在住院记录的人
            if (FactorTimeStatusEnum.YES.getType().equals(factorTimeStatus) && null == factorTime) {
                factorDataList = vrInpatientVisitRecordDAO.executeFactorForInpatientStatus(deptIdList, null, null, patientIdList, false, isLoopExecute, followUpRouteDetailFactor.getRouteDetailId(), followType);
                factorDataAnswerList = fusAnswerInHospitalInfoDAO.executeFactorForInpatientStatus(deptIdList, dateSection[0], dateSection[1], patientIdList, false, isLoopExecute, followUpRouteDetailFactor.getRouteDetailId(), followType);
                factorDataList.addAll(factorDataAnswerList);
            }
            // 6.不存在住院记录的人
            if (FactorTimeStatusEnum.NO.getType().equals(factorTimeStatus) && null == factorTime) {
                if (CommonUtils.isNotEmpty(patientIdList)) {
                    //这段时间内无住院记录的患者ID集合
                    List<String> resultList = new ArrayList<String>();
                    factorDataList = vrInpatientVisitRecordDAO.executeFactorForInpatientStatus(deptIdList, null, null, patientIdList, false, isLoopExecute, followUpRouteDetailFactor.getRouteDetailId(), followType);
                    factorDataAnswerList = fusAnswerInHospitalInfoDAO.executeFactorForInpatientStatus(deptIdList, dateSection[0], dateSection[1], patientIdList, false, isLoopExecute, followUpRouteDetailFactor.getRouteDetailId(), followType);
                    factorDataList.addAll(factorDataAnswerList);
                    //这段时间内有住院记录的患者ID集合
                    List<String> tempList = new ArrayList<String>();
                    if (CommonUtils.isNotEmpty(patientIdList)) {
                        for (FactorData factorData : factorDataList) {
                            tempList.add(factorData.getPatientId());
                        }
                    }
                    //求差集
                    resultList.addAll(patientIdList);
                    resultList.removeAll(tempList);
                    if (CommonUtils.isNotEmpty(resultList)) {
                        // 这段时间内无住院记录的患者FactorData列表
                        List<FactorData> resultFactorData = new ArrayList<>();
                        for (String patientId : resultList) {
                            FactorData factorData = new FactorData();
                            factorData.setPatientId(patientId);
                            resultFactorData.add(factorData);
                        }
                        factorDataList.addAll(resultFactorData);
                    }
                }
                factorDataList = null;
            }
        }
        if (CommonUtils.isNotEmpty(factorDataList)) {
            //对factorDataList进行数据转换
            executeFactorResponse = this.factorDataTransform(factorDataList, followUpRouteDetailFactor);
        }
        return BaseRespUtil.setResultSuccess(executeFactorResponse);
    }

    /**
     * 执行专病拓展属性因素
     *
     * @param followUpRouteDetailFactor 因素记录
     * @param isLoopExecute             循环执行机制 0 不执行 1 执行
     * @param followType                随访大类类型 1-专病随访，2-院后随访，3-满意度随访
     * @param patientIdList             病人id集合，如果传入不为空的话，可以根据传入的参数缩小检索范围
     * @return org.atag.core.base.BaseResponse<specialist.bean.response.ExecuteFactorResponse>
     * @throws
     * @Author:ChenJij
     */
    @Override
    public BaseResponse<ExecuteFactorResponse> executeFactorForSpecificDiseaseDevelopmentAttribute(FollowUpRouteDetailFactor followUpRouteDetailFactor, Byte isLoopExecute, String followType, List<String> patientIdList) {
        ExecuteFactorResponse executeFactorResponse = new ExecuteFactorResponse();
        //查询因素详情列表
        List<FollowUpRouteDetailFactorRelation> detailFactorRelationList = detailFactorRelationDAO.queryFactorRelationByRouteDetailFactorId(followUpRouteDetailFactor.getRouteDetailFactorId(),
                followUpRouteDetailFactor.getRouteDetailId());
        if (CommonUtils.isEmpty(detailFactorRelationList)) {
            return BaseRespUtil.setResultSuccess(executeFactorResponse);
        }

        //因素id集合，就是专病拓展属性id集合
        List<String> factoryIdList = new ArrayList<>();
        for (FollowUpRouteDetailFactorRelation relation : detailFactorRelationList) {
            factoryIdList.add(relation.getFactorSpecialistId());
        }

        Byte factorTime = followUpRouteDetailFactor.getFactorTime();
        Date[] dateSection = new Date[2];
        if (OUTPATIENT_DIAGNOSIS.getType().equals(followUpRouteDetailFactor.getFactorType())) {
            dateSection = this.getBusinessTimeRange(followUpRouteDetailFactor.getFactorTimeType(), followUpRouteDetailFactor.getFactorTimeValue(),
                    followUpRouteDetailFactor.getFactorTime(), DiagnosisAndTreatmentDataTypeEnum.OUTPATIENT_RECORDS.getType());
        } else if (FollowFactorTypeEnum.IN_HOSPITAL_DIAGNOSIS.getType().equals(followUpRouteDetailFactor.getFactorType()) || FollowFactorTypeEnum.OUT_HOSPITAL_DIAGNOSIS.getType().equals(followUpRouteDetailFactor.getFactorType())) {
            dateSection = this.getBusinessTimeRange(followUpRouteDetailFactor.getFactorTimeType(), followUpRouteDetailFactor.getFactorTimeValue(),
                    followUpRouteDetailFactor.getFactorTime(), DiagnosisAndTreatmentDataTypeEnum.HOSPITALIZATION_RECORDS.getType());
        }
        //查询入组专病分期记录列表
        List<FactorData> factorDataList = groupRecordExtendPropertyDAO.executeFactorForDiseasePeriod(factoryIdList,
                dateSection[0], dateSection[1], patientIdList, isLoopExecute, followUpRouteDetailFactor.getRouteDetailId(), followType);
        if (CommonUtils.isNotEmpty(factorDataList)) {
            //对factorDataList进行数据转换
            executeFactorResponse = this.factorDataTransform(factorDataList, followUpRouteDetailFactor);
        }
        return BaseRespUtil.setResultSuccess(executeFactorResponse);
    }

    /**
     * @Author:FangZhiYi
     * @Description 根据时间因素处理业务时间区间
     * @Params [factorTimeType 时间因素类型，1满，2内,
     * @Params [factorTimeValue 因素时间天数
     * @Params [factorTime 因素时间 1 天 2 周 3 月 4 年
     * @Params [dateType 诊疗数据类型，枚举类DiagnosisAndTreatmentDataType
     * @Return java.util.Date[] 数组下标0的为开始时间，数组下标1的为结束时间,在SQL中，开始时间<业务时间<结束时间
     * @Data Created in 2022/5/27 10:48
     * @Moddified By:
     */
    private Date[] getBusinessTimeRange(Byte factorTimeType, Integer factorTimeValue, Byte factorTime,
                                        Integer dateType) {
        Date[] returnDate = new Date[2];
        Date now = new Date();
        Calendar calendar = Calendar.getInstance();
        calendar.setTime(now);
        int factorTimeNumber = 0;
        if (CommonUtils.isNotNull(factorTime) && CommonUtils.isNotNull(factorTimeValue)) {
            //因素时间 1 天 2 周 3 月 4 年
            switch (factorTime) {
                case 1:
                    factorTimeNumber = factorTimeValue;
                    break;
                case 2:
                    factorTimeNumber = factorTimeValue * 7;
                    break;
                case 3:
                    factorTimeNumber = factorTimeValue * 30;
                    break;
                case 4:
                    factorTimeNumber = factorTimeValue * 365;
                    break;
                default:
                    break;
            }
        }
        calendar.add(Calendar.DATE, -factorTimeNumber);
        if (null == factorTimeType) {
            return returnDate;
        }
        // 时间因素类型，1满，2内
        if (factorTimeType == 1) {
            returnDate[0] = null;
            returnDate[1] = calendar.getTime();
        } else {
            returnDate[0] = calendar.getTime();
            returnDate[1] = now;
        }
        //记录有效时间
        if (null != dateType) {
            VrSynchroSettings settings = synchroSettingsDAO.get(dateType);
            int storageMonth = settings.getStorageMonth();
            if (0 != storageMonth) {
                calendar.setTime(now);
                calendar.add(Calendar.DATE, -storageMonth * 30);
                Date startTime = calendar.getTime();
                if (null == returnDate[0] || startTime.getTime() > returnDate[0].getTime()) {
                    returnDate[0] = startTime;
                }
            }
        }
        return returnDate;
    }

    /**
     * @Author:FangZhiYi
     * @Description 对factorDataList进行数据转换
     * @Params [factorDataList, followFactorType]
     * @Return specialist.bean.response.ExecuteFactorResponse
     * @Data Created in 2022/5/27 16:37
     * @Moddified By:
     */
    private ExecuteFactorResponse factorDataTransform(List<FactorData> factorDataList, FollowUpRouteDetailFactor followUpRouteDetailFactor) {
        ExecuteFactorResponse executeFactorResponse = new ExecuteFactorResponse();
        //出参的患者列表
        List<String> patientIdList = new ArrayList<>();
        //出参的个人的因素数据
        Map<String, FactorData> factorMap = new HashMap<>();
        for (FactorData factorData : factorDataList) {
            factorData.setRouteDetailFactorId(followUpRouteDetailFactor.getRouteDetailFactorId());
            factorData.setFactorConditionType(followUpRouteDetailFactor.getFactorConditionType());
            factorData.setFactorType(followUpRouteDetailFactor.getFactorType());
            factorData.setSort(followUpRouteDetailFactor.getSort());
            patientIdList.add(factorData.getPatientId());
            //已判断是否已存在该患者
            if (factorMap.containsKey(factorData.getPatientId())) {
                Date dateOld = null;
                Date dateNew = null;
                switch (followUpRouteDetailFactor.getFactorType()) {
                    //随访因素类别字典见 FollowFactorTypeEnum
                    case 1:
                        //门诊诊断
                    case 2:
                        //入院诊断
                    case 3:
                        //出院诊断
                        dateNew = factorData.getDiagnosisTime();
                        dateOld = factorMap.get(factorData.getPatientId()).getDiagnosisTime();
                        break;
                    case 4:
                        //接诊医生
                        dateNew = factorData.getVisitTime();
                        dateOld = factorMap.get(factorData.getPatientId()).getVisitTime();
                        break;
                    case 5:
                        //责任医生
                        dateNew = factorData.getDischargeTime();
                        dateOld = factorMap.get(factorData.getPatientId()).getDischargeTime();
                        break;
                    case 6:
                        //指标
                        dateNew = factorData.getReportTime();
                        dateOld = factorMap.get(factorData.getPatientId()).getReportTime();
                        break;
                    case 7:
                        //手术名称
                        dateNew = factorData.getOperationEndTime();
                        dateOld = factorMap.get(factorData.getPatientId()).getOperationEndTime();
                        break;
                    case 9:
                        //专病分期
                        dateNew = factorData.getStagesRecordCreateTime();
                        dateOld = factorMap.get(factorData.getPatientId()).getStagesRecordCreateTime();
                        break;
                    case 10:
                        //专病拓展属性
                        dateNew = factorData.getStagesRecordCreateTime();
                        dateOld = factorMap.get(factorData.getPatientId()).getStagesRecordCreateTime();
                        break;
                    default:
                        break;
                }
                //取时间最晚的一条
                if (dateOld != null && dateNew != null && dateNew.getTime() > dateOld.getTime()) {
                    factorMap.put(factorData.getPatientId(), factorData);
                } else if (dateOld == null && dateNew != null) {
                    factorMap.put(factorData.getPatientId(), factorData);
                }
            } else {
                factorMap.put(factorData.getPatientId(), factorData);
            }
        }
        executeFactorResponse.setPatientIdList(patientIdList);
        executeFactorResponse.setFactorDataMap(factorMap);
        return executeFactorResponse;
    }

    /**
     * 根据不同的因素类型返回因素时间
     *
     * @param
     * @return java.util.Date
     * @throws
     * @author tongtp
     * @date 2022/6/1 9:11
     */
    private Date getFactorDate(FactorData factorData) {
        //根据因素类型调用
        switch (FollowFactorTypeEnum.getEnumByType(factorData.getFactorType())) {
            case OUTPATIENT_DIAGNOSIS:
            case IN_HOSPITAL_DIAGNOSIS:
            case OUT_HOSPITAL_DIAGNOSIS:
                return factorData.getDiagnosisTime();
            case RECEIVE_DOCTOR:
                return factorData.getVisitTime();
            case DUTY_DOCTOR:
                return factorData.getDischargeTime();
            case CRUCIAL_INDEX:
                return factorData.getReportTime();
            case SURGICAL_NAME:
                return factorData.getOperationEndTime();
            case MEDICAL_ADVICE_NAME:
                return factorData.getExecutionTime();
            case SPECIALIST_STAGE:
                return factorData.getStagesRecordCreateTime();
            case SPECIALIST_ATTRIBUTE:
                return factorData.getExtendTime();
            case OUTPATIENT_STATUS:
                return factorData.getVisitTime();
            case INPATIENT_STATUS:
                return factorData.getDischargeTime();
            case ROUTE_BRANCH:
                return null;
            default:
                return null;
        }
    }

    /**
     * 处理因素满足的人员因素数据
     *
     * @param currentList
     * @param patientInfoMap
     * @param factorDataMap
     * @return void
     * @throws
     * @author tongtp
     * @date 2022/5/30 13:49
     */
    private void handlePatientInfoMap(List<String> currentList, Map<String, List<FactorData>> patientInfoMap,
                                      Map<String,
                                              FactorData> factorDataMap) {
        if (!CollectionUtils.isEmpty(currentList)) {
            for (String patientId :
                    currentList) {
                if (CommonUtils.isNotEmpty(factorDataMap.get(patientId))) {
                    if (CollectionUtils.isEmpty(patientInfoMap.get(patientId))) {
                        List<FactorData> list = new ArrayList<>();
                        patientInfoMap.put(patientId, list);
                        list.add(factorDataMap.get(patientId));
                    } else {
                        patientInfoMap.get(patientId).add(factorDataMap.get(patientId));
                    }
                }
            }
            factorDataMap.clear();
        }
    }

    /**
     * 处理门诊就诊、住院状态的因素
     *
     * @param followUpRoute
     * @param isLoopExecute
     * @param currentList
     * @param currentInit
     * @param statusFactorList
     * @return boolean
     * @throws
     * @author tongtp
     * @date 2022/5/30 10:25
     */
    private boolean handleStatusFactorList(FollowUpRoute followUpRoute, Byte isLoopExecute, List<String> currentList,
                                           boolean currentInit, List<FollowUpRouteDetailFactor> statusFactorList,
                                           Map<String, List<FactorData>> patientInfoMap) throws ControllerException {
        if (!CollectionUtils.isEmpty(statusFactorList)) {
            for (FollowUpRouteDetailFactor temp :
                    statusFactorList) {
                currentInit = handleFactorForAnd(followUpRoute, isLoopExecute, currentList, currentInit, temp,
                        patientInfoMap);
            }
            statusFactorList.clear();
        }
        return currentInit;
    }

    /**
     * 处理运算符是and的因素
     *
     * @param followUpRoute
     * @param isLoopExecute
     * @param currentList
     * @param currentInit
     * @param followUpRouteDetailFactor
     * @return boolean
     * @throws
     * @author tongtp
     * @date 2022/5/27 16:40
     */
    private boolean handleFactorForAnd(FollowUpRoute followUpRoute, Byte isLoopExecute, List<String> currentList,
                                       boolean currentInit, FollowUpRouteDetailFactor followUpRouteDetailFactor,
                                       Map<String, List<FactorData>> patientInfoMap) throws ControllerException {
        if (currentInit && CollectionUtils.isEmpty(currentList)) {
            //currentList已经初始化过，还是为空的，相连的and条件直接跳过执行
            return currentInit;
        }
        //调用因素执行服务
        ExecuteFactorResponse factorResponse = executeFactor(followUpRouteDetailFactor,
                isLoopExecute, followUpRoute,
                currentList, currentInit, patientInfoMap);
        List<String> patientIdList = factorResponse.getPatientIdList();
        if (!currentInit) {
            if (CollectionUtils.isEmpty(currentList)) {
                currentList.addAll(patientIdList);
            } else {
                //专病随访，就算是
                //求交集
                currentList.retainAll(patientIdList);
            }
            currentInit = true;
        } else {
            //求交集
            currentList.retainAll(patientIdList);
        }
        //处理因素满足的人员因素数据
        handlePatientInfoMap(currentList, patientInfoMap, factorResponse.getFactorDataMap());
        return currentInit;
    }

    /**
     * 执行医嘱名称因素
     *
     * @param followUpRouteDetailFactor 因素记录
     * @param isLoopExecute             循环执行机制 0 不执行 1 执行
     * @param followType                随访大类类型 1-专病随访，2-院后随访，3-满意度随访
     * @param patientIdList             病人id集合，如果传入不为空的话，可以根据传入的参数缩小检索范围
     * @return org.atag.core.base.BaseResponse<specialist.bean.response.ExecuteFactorResponse>
     * @throws
     */
    @Override
    public BaseResponse<ExecuteFactorResponse> executeFactorForMedicalAdviceName(FollowUpRouteDetailFactor followUpRouteDetailFactor, Byte isLoopExecute, String followType, List<String> patientIdList) {
        //todo 3.5.01迭代不实现
        return new BaseResponse();
    }

    /**
     * 执行因素
     *
     * @param factor         因素记录
     * @param isLoopExecute  环执行机制 0 不执行 1 执行
     * @param followUpRoute  随访路径
     * @param patientIdList  病人id集合，如果传入不为空的话，可以根据传入的参数缩小检索范围
     * @param currentInit    currentList是否完成初始化
     * @param patientInfoMap 病人因素信息存储集合，key是病人id，value是按顺序存储的因素数据集合
     * @return org.atag.core.base.BaseResponse<specialist.bean.response.ExecuteFactorResponse>
     * @throws
     */
    private ExecuteFactorResponse executeFactor(FollowUpRouteDetailFactor factor,
                                                Byte isLoopExecute,
                                                FollowUpRoute followUpRoute,
                                                List<String> patientIdList,
                                                boolean currentInit,
                                                Map<String, List<FactorData>> patientInfoMap) throws ControllerException {
        BaseResponse<ExecuteFactorResponse> baseResponse = new BaseResponse<>();
        //随访大类类型 1-专病随访，2-院后随访，3-满意度随访
        String followType = followUpRoute.getFollowType();
        if (FollowTypeEnum.FUS_SPECIALIST.getType().equals(followType) && CollectionUtils.isEmpty(patientIdList)) {
            //只有是专病随访，且patientIdList为空执行这块逻辑，如果patientIdList不为空则说明已经执行过下面这个逻辑了不用重复执行

            //专病随访的，如果tempList为空则直接返回
            //tempList病人id集合(专病随访必不能为空,查询该病种有效的入组患者的病人id)
            List<String> tempList =
                    produceExecutionListDAO.queryPatientIdByChronicDiseaseId(followUpRoute.getDiseaseTypeId());
            if (CollectionUtils.isEmpty(tempList)) {
                ExecuteFactorResponse data = new ExecuteFactorResponse();
                data.setPatientIdList(new ArrayList<>());
                data.setFactorDataMap(new HashMap<>());
                return data;
            } else {
                patientIdList = tempList;
            }
        }
        //根据因素类型调用
        switch (FollowFactorTypeEnum.getEnumByType(factor.getFactorType())) {
            case OUTPATIENT_DIAGNOSIS:
            case IN_HOSPITAL_DIAGNOSIS:
            case OUT_HOSPITAL_DIAGNOSIS:
                baseResponse = this.executeFactorForDiagnosis(factor, isLoopExecute, followType, patientIdList);
                break;
            case RECEIVE_DOCTOR:
                baseResponse = this.executeFactorForAttendingDoctor(factor, isLoopExecute, followType, patientIdList);
                break;
            case DUTY_DOCTOR:
                baseResponse = this.executeFactorForResponsibleDoctor(factor, isLoopExecute, followType, patientIdList);
                break;
            case CRUCIAL_INDEX:
                baseResponse = this.executeFactorForRelatedIndicators(factor, isLoopExecute, followType, patientIdList);
                break;
            case SURGICAL_NAME:
                baseResponse = this.executeFactorForOperation(factor, isLoopExecute, followType, patientIdList);
                break;
            case MEDICAL_ADVICE_NAME:
                baseResponse = this.executeFactorForMedicalAdviceName(factor, isLoopExecute, followType, patientIdList);
                break;
            case SPECIALIST_STAGE:
                baseResponse = this.executeFactorForSpecificDiseaseStage(factor, isLoopExecute, followType,
                        patientIdList);
                break;
            case SPECIALIST_ATTRIBUTE:
                baseResponse = this.executeFactorForSpecificDiseaseDevelopmentAttribute(factor, isLoopExecute,
                        followType, patientIdList);
                break;
            case OUTPATIENT_STATUS:
            case INPATIENT_STATUS:
                //获取同组因素的病人因素时间集合
                Map<String, Date> patientFactorTimeMap = getPatientFactorTimeMap(patientIdList, currentInit,
                        patientInfoMap);
                logger.info("executeFactor--currentInit:{},patientInfoMap:{},patientFactorTimeMap:{}",
                        currentInit,
                        JSON.toJSONString(patientInfoMap),
                        JSON.toJSONString(patientFactorTimeMap));
                //门诊就诊和住院状态 选择否，而且没有选择时间属性的时候执行下面的逻辑
                //门诊就诊和住院状态,这个因素单独存在时(patientIdList为空，且执行到这块，说明就是单独存在的)。需要查询patientIdList
                //专病的查询该病人有效的入组患者的病人id(前面的逻辑已经查询过了)，所以这里只要处理院后和满意度的就行了(院后和满意度的查询对应就诊类型的所有病人id)
                if (FactorTimeStatusEnum.NO.getType().equals(factor.getFactorTimeStatus()) && CommonUtils.isNull(factor.getFactorTime()) && CommonUtils.isEmpty(patientIdList)) {
                    patientIdList = getPatientIdListByVisitType(followUpRoute.getVisitType(),
                            followUpRoute.getDepartmentId());
                }
                baseResponse = this.executeFactorForOutpatientInpatientStatus(factor, isLoopExecute, followType,
                        patientIdList, patientFactorTimeMap);
                break;
            case ROUTE_BRANCH:
                baseResponse = this.executeFactorForPathBranch(factor, isLoopExecute, followType, patientIdList);
                break;
            default:
                break;
        }
        logger.info("执行因素-因素信息factor:{},isLoopExecute:{},followType:{},patientIdList:{},因素执行返回结果baseResponse:{}",
                JSON.toJSONString(factor), isLoopExecute, followType, patientIdList,
                JSON.toJSONString(baseResponse));
        if (ResultCode.SUCCESS == baseResponse.getCode()) {
            ExecuteFactorResponse data = baseResponse.getData();
            if (data == null) {
                data = new ExecuteFactorResponse();
            }
            if (data.getPatientIdList() == null) {
                data.setPatientIdList(new ArrayList<>());
            }
            if (data.getFactorDataMap() == null) {
                data.setFactorDataMap(new HashMap<>());
            }
            return data;
        } else {
            throw new ControllerException(ResultCode.ERROR, baseResponse.getMessage());
        }
    }

    /**
     * 根据就诊记录类型查询
     *
     * @param visitType
     * @return java.util.List<java.lang.String>
     * @throws
     * @author tongtp
     * @date 2022/6/14 16:08
     */
    private List<String> getPatientIdListByVisitType(Byte visitType, String departmentId) {
        if (CommonUtils.isNull(visitType)) {
            return new ArrayList<>();
        }
        List<String> departmentIds = null;
        if (CommonUtils.isNotNull(departmentId)) {
            departmentIds = Arrays.asList(departmentId.split(","));
        }
        switch (getEnumByKey(visitType)) {
            case OUTPATIENT_VISIT_RECORD:
                return vrOutpatientVisitRecordDAO.queryAllPatientId(departmentIds);
            case INPATIENT_VISIT_RECORD:
                return vrInpatientVisitRecordDAO.queryAllPatientId(departmentIds);
            case PHYSICAL_EXAMINATION_RECORDS:
                return new ArrayList<>();
            case SURGICAL_RECORD:
                return vrSurgicalRecordDAO.queryAllPatientId(departmentIds);
            case INSPECTION_RECORD:
                return vrApplicationFormRecordDAO.queryAllPatientId("1", departmentIds);
            case CHECK_RECORD:
                return vrApplicationFormRecordDAO.queryAllPatientId("2", departmentIds);
            case DISPENSING_RECORD:
                return vrDispensingRecordDAO.queryAllPatientId(departmentIds);
            case TREATMENT_RECORD:
                return vrApplicationFormRecordDAO.queryAllPatientId("3", departmentIds);
            default:
                return new ArrayList<>();
        }
    }

    /**
     * 获取同组因素的病人因素时间集合
     *
     * @param patientIdList
     * @param currentInit
     * @param patientInfoMap
     * @return java.util.Map<java.lang.String, java.util.Date>
     * @throws
     * @author tongtp
     * @date 2022/6/14 14:00
     */
    private Map<String, Date> getPatientFactorTimeMap(List<String> patientIdList, boolean currentInit, Map<String,
            List<FactorData>> patientInfoMap) {
        //同组因素的病人因素时间集合计算
        Map<String, Date> patientFactorTimeMap = new HashMap<>();
        if (currentInit) {
            //currentInit为true说明已有同组的因素完成了执行，这个时候才有同组的因素时间需要处理
            if (CommonUtils.isNotEmpty(patientIdList)) {
                for (String patientId :
                        patientIdList) {
                    List<FactorData> factorDatas = patientInfoMap.get(patientId);
                    if (CommonUtils.isNotEmpty(factorDatas)) {
                        //实现排序，因为执行因素的时候,门诊就诊和住院状态的因素是会排在同组因素后面执行的，所以在算因素时间时要还原原有排序计算
                        Collections.sort(factorDatas);
                        Date patientFactorTime = null;
                        //这里要倒序遍历
                        for (int i = factorDatas.size() - 1; i >= 0; i--) {
                            FactorData temp = factorDatas.get(i);
                            patientFactorTime = DateTimeUtil.getMaxDate(patientFactorTime, getFactorDate(temp));
                            if (FactorConditionTypeEnum.OR.getType().equals(temp.getFactorConditionType())) {
                                //如果当前这个是or,说明上一个就不是同一组的了，所以跳出
                                break;
                            }
                        }
                        patientFactorTimeMap.put(patientId, patientFactorTime);
                    }
                }
            }
        }
        return patientFactorTimeMap;
    }

    /**
     * @param diseaseTypeId
     * @param followUpRouteDetail
     * @param routeDetailId
     * @param advanceNotifyDate
     * @throws
     * @description: 计算得到提前通知时间-天数
     * @return: java.lang.Integer
     * @author: tongtp
     * @date: 2020/7/28 17:39
     */
    @Override
    public Integer getAdvanceNotifyDate(Long diseaseTypeId, FollowUpRouteDetail followUpRouteDetail,
                                        Long routeDetailId, Integer advanceNotifyDate) {
        if (followUpRouteDetail.getNotifyDate() == null) {
            logger.info("diseaseTypeId:{},RouteDetailId:{}," +
                            "IsNotify:{}，NotifyDate:{},随访计划需要通知患者但是通知患者时间为空，暂停生成计划",
                    diseaseTypeId,
                    routeDetailId, followUpRouteDetail.getIsNotify(),
                    followUpRouteDetail.getNotifyDate());
            return null;
        }
        //需要通知患者时不能为空，通知患者时间，1当前天、2提前一天、 3提前2天、4提前3天、5提前4天、6提前5天、7提前6天、8提前一周
        advanceNotifyDate = getAdvanceNotifyDate(advanceNotifyDate, followUpRouteDetail.getNotifyDate());
        if (advanceNotifyDate > 0) {
            logger.info("diseaseTypeId:{},RouteDetailId:{}," +
                            "IsNotify:{}，NotifyDate:{},随访计划需要通知患者但是通知患者时间为字典之外的值，暂停生成计划",
                    diseaseTypeId,
                    routeDetailId, followUpRouteDetail.getIsNotify(),
                    followUpRouteDetail.getNotifyDate());
            return null;
        }
        return advanceNotifyDate;
    }

    /**
     * 通过机构代码和科室代码查询科室id(内码)
     *
     * @param organizationId
     * @param departmentId
     * @return String
     */
    @Override
    public String getDeptIdByLocalDeptId(String organizationId, String departmentId) {
        Organization organization = organizationRpcService.getOrgDetailByOrgCode(organizationId);
        if (organization != null) {
            Dept dept = deptMainRpcService.getDeptByLocalDeptId(organization.getOrgId(), departmentId);
            if (dept != null) {
                return dept.getDeptId();
            }
        }
        return null;
    }

    /**
     * 通过机构代码查询租户id
     *
     * @param organizationId
     * @return String
     */
    @Override
    public String getTenantIdByOrgCode(String organizationId) {
        Organization organization = organizationRpcService.getOrgDetailByOrgCode(organizationId);
        if (organization != null) {
            return organization.getTenantId();
        }
        return null;
    }

    /**
     * 保存因素数据使用记录
     *
     * @param followType          随访大类类型 1-专病随访，2-院后随访，3-满意度随访
     * @param routeDetailId       子路径id
     * @param factorDataList      因素数据集合
     * @param teamChronicGroupId  入组记录 id-专病随访必填
     * @param fusAfterHosRecordId 随访记录id-院后随访和满意度随访必填
     * @return void
     * @throws
     * @author tongtp
     * @date 2022/6/7 10:00
     */
    @Override
    public void saveFusFactorDataRecord(String followType, Long routeDetailId, List<FactorData> factorDataList,
                                        Long teamChronicGroupId, String fusAfterHosRecordId) {
        if (CommonUtils.isNotEmpty(factorDataList)) {
            for (FactorData factorData :
                    factorDataList) {
                FusFactorDataRecord fusFactorDataRecord = new FusFactorDataRecord();
                fusFactorDataRecord.setId(Utils.getUUID());
                fusFactorDataRecord.setFollowType(followType);
                fusFactorDataRecord.setRouteDetailId(routeDetailId);
                fusFactorDataRecord.setTeamChronicGroupId(teamChronicGroupId);
                fusFactorDataRecord.setRecordId(fusAfterHosRecordId);
                fusFactorDataRecord.setDataSource(factorData.getDataSource());
                fusFactorDataRecord.setRouteDetailFactorId(factorData.getRouteDetailFactorId());
                fusFactorDataRecord.setFactorConditionType(factorData.getFactorConditionType());
                fusFactorDataRecord.setFactorType(factorData.getFactorType());
                fusFactorDataRecord.setPatientId(factorData.getPatientId());
                fusFactorDataRecord.setDiagnosticRecordId(factorData.getDiagnosticRecordId());
                fusFactorDataRecord.setDiagnosisServiceType(factorData.getDiagnosisServiceType());
                fusFactorDataRecord.setDiseasesCode(factorData.getDiseasesCode());
                fusFactorDataRecord.setDiseasesName(factorData.getDiseasesName());
                fusFactorDataRecord.setDiagnosisTime(factorData.getDiagnosisTime());
                fusFactorDataRecord.setOperationRecordId(factorData.getOperationRecordId());
                fusFactorDataRecord.setOperationCode(factorData.getOperationCode());
                fusFactorDataRecord.setOperationName(factorData.getOperationName());
                fusFactorDataRecord.setOperationEndTime(factorData.getOperationEndTime());
                fusFactorDataRecord.setIndexRecordId(factorData.getIndexRecordId());
                fusFactorDataRecord.setIndexCode(factorData.getIndexCode());
                fusFactorDataRecord.setIndexName(factorData.getIndexName());
                fusFactorDataRecord.setIndexResult(factorData.getIndexResult());
                fusFactorDataRecord.setReportTime(factorData.getReportTime());
                fusFactorDataRecord.setStagesRecordId(factorData.getStagesRecordId());
                fusFactorDataRecord.setStagesCode(factorData.getStagesCode());
                fusFactorDataRecord.setVisitRecordId(factorData.getVisitRecordId());
                fusFactorDataRecord.setOrganizationId(factorData.getOrganizationId());
                fusFactorDataRecord.setDoctorId(factorData.getDoctorId());
                fusFactorDataRecord.setDoctorName(factorData.getDoctorName());
                fusFactorDataRecord.setVisitTime(factorData.getVisitTime());
                fusFactorDataRecord.setHospitalRecordId(factorData.getHospitalRecordId());
                fusFactorDataRecord.setDischargeTime(factorData.getDischargeTime());
                fusFactorDataRecord.setStagesName(factorData.getStagesName());
                fusFactorDataRecord.setStagesRecordCreateTime(factorData.getStagesRecordCreateTime());
                fusFactorDataRecord.setGroupChronicRecordId(factorData.getGroupChronicRecordId());
                fusFactorDataRecord.setExtendId(factorData.getExtendId());
                fusFactorDataRecord.setName(factorData.getName());
                fusFactorDataRecord.setExtendTime(factorData.getExtendTime());
                fusFactorDataRecord.setGmtCreate(new Date());
                fusFactorDataRecordDAO.save(fusFactorDataRecord);
            }
        }
    }

    /**
     * @param advanceNotifyDate
     * @param notifyDate
     * @throws
     * @description: 计算提前通知天数
     * @return: java.lang.Integer
     * @author: tongtp
     * @date: 2020/8/11 16:07
     */
    @Override
    public Integer getAdvanceNotifyDate(Integer advanceNotifyDate, Byte notifyDate) {
        //需要通知患者时不能为空，通知患者时间，1当前天、2提前一天、 3提前2天、4提前3天、5提前4天、6提前5天、7提前6天、8提前一周
        switch (notifyDate) {
            case (byte) 1:
                advanceNotifyDate = 0;
                break;
            case (byte) 2:
                advanceNotifyDate = -1;
                break;
            case (byte) 3:
                advanceNotifyDate = -2;
                break;
            case (byte) 4:
                advanceNotifyDate = -3;
                break;
            case (byte) 5:
                advanceNotifyDate = -4;
                break;
            case (byte) 6:
                advanceNotifyDate = -5;
                break;
            case (byte) 7:
                advanceNotifyDate = -6;
                break;
            case (byte) 8:
                advanceNotifyDate = -7;
                break;
            default:
                break;
        }
        return advanceNotifyDate;
    }
}
